﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

/*
 * KTR Map Editor Clocktower Edition v.2.0 :D
 * @author Blake Gross
 * 
 * This map editor currently works for 32 by 32 tile map design
 * 
 */ 

namespace LevelEditor
{
    public partial class EditorForm : Form
    {
        public PictureBox[,] objects;
        public PictureBox[,] animation;
        public String mapName;
        public String currentTile;
        public List<List<String>> objectsList;
        public List<List<String>> animationArray;
        public int layerNum;
        public int counter;

        public int tempXOffset;
        public int tempYOffset;
        public int tempWidth;
        public int tempHeight;
        public int tempInterval;
        public int tempFrames;

        public string tempNextRoom;
        public bool tempLocked;
        public string tempExitLoc;
        public int tempAreaNum;

        public int tempXSpeed;
        public int tempYSpeed;
        public string tempEnd1Pos;
        public string tempEnd2Pos;

        public char tempLeverEffect;
        public int tempLeverObjectAffected;

        public int tempBeamVisibility;

        public List<String> tempListString;

        public EditorForm()
        {
            InitializeComponent();
            layerNum = 1;
        }

        /// <summary>
        /// Paramaterized Constructor for creating a new map
        /// </summary>
        /// <param name="x">The number of rows</param>
        /// <param name="y">The number of columns</param>
        /// <param name="name">The name of the map</param>
        public EditorForm(int x, int y, String name)
        {
            InitializeComponent();
            objects = new PictureBox[x, y];
            objectsList = new List<List<String>>();
            tempListString = new List<String>();
            animation = new PictureBox[x, y];
            animationArray = new List<List<String>>();
            mapName = name;
            this.Name = mapName;
            saveTextBox.Text = mapName + ".ktr";
            this.Select();
            if ((230 + ((x + 1) * 16)) > Width)
            {
                Width = (230 + ((x + 1) * 16)) + 16;
            }
            if ((3 + ((y + 1) * 32)) > Height)
            {
                Height = (10 + ((y + 1) * 16)) + 16;
            }
            CreateMap();
            //this.Refresh();

        }

        /// <summary>
        /// Paramaterized Contructor for loading a map
        /// </summary>
        /// <param name="filePath">Where the file is coming from</param>
        public EditorForm(String filePath)
        {
            InitializeComponent();

            ReadFiles(filePath);
        }

        /// <summary>
        /// Submits the pathbox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void submitButton_Click(object sender, EventArgs e)
        {
            currentTile = pathBox.Text;      // sets the image in the imageBox to the image
            imageTile.ImageLocation = currentTile;
            imageTile.Image = new Bitmap(imageTile.ImageLocation);
        }

        /// <summary>
        /// Clears the pathBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void clearButton_Click(object sender, EventArgs e)
        {
            pathBox.Text = "";
        }

        /// <summary>
        /// Calls the loadForm
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadForm load = new LoadForm();
            load.ShowDialog();
            this.Dispose();
            load.Dispose();
        }

        /// <summary>
        /// Calls the new form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddNew add = new AddNew();      // creates a new addBox
            add.ShowDialog();               // calls the new one
            Dispose();                      // destroys the current box
        }

        /// <summary>
        /// Creates all of the boxes for the map
        /// </summary>
        public void CreateMap()
        {
            // goes through the array and creates a tile at each part of it
            for (int i = 0; i < objects.GetLength(0); i++)
            {
                for (int j = 0; j < objects.GetLength(1); j++)
                {
                    PictureBox objPic = new PictureBox();                                        // creates a new picBox
                    objPic.Size = new Size(16, 16);                                                 // shrinks the size of the picturebox
                    Point objPicPoint = new Point(230 + ((i + 1) * 16), 10 + ((j + 1) * 16));     // adds the proper amount to each
                    objPic.ImageLocation = "blank.png";                                            // sets a default picture
                    objPic.SizeMode = PictureBoxSizeMode.StretchImage;
                    objPic.Location = objPicPoint;
                    objPic.Name = "" + objPic + i + j;
                    objects[i, j] = objPic;

                    PictureBox animationPic = new PictureBox();
                    animationPic.Size = new Size(16, 16);
                    Point animationPicPoint = new Point(230 + ((i + 1) * 16), 10 + ((j + 1) * 16));
                    animationPic.ImageLocation = "blank.png";
                    animationPic.SizeMode = PictureBoxSizeMode.StretchImage;
                    animationPic.Location = animationPicPoint;
                    animationPic.Name = "" + animationPic + i + j;
                    animation[i, j] = animationPic;
                }
            }
            DrawLayer(objects, animation);
        }


        /// <summary>
        /// Changes the pictureboxes if clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EditorForm_Click(object sender, EventArgs e)
        {
            try
            {
                PictureBox pic = (PictureBox)sender;
                int numTilesX;
                int numTilesY;

                pic.ImageLocation = imageTile.ImageLocation;
                pic.Image = imageTile.Image;
                pic.Width = imageTile.Image.Width;
                pic.Height = imageTile.Image.Height;
                while (pic.Width % 16 != 0) { pic.Width++; }
                while (pic.Height % 16 != 0) { pic.Height++; }

                numTilesX = (pic.Width / 16);        // gets the number of tiles that need replaces in certain directions
                numTilesY = (pic.Height / 16);

                int mapLocationX = ((pic.Location.X - 230) / 16) - 1;    // formula derived from original placement of tiles on the board
                int mapLocationY = ((pic.Location.Y - 10) / 16) - 1;

                CheckRemoval(pic);
                if (counter == 0 && imageTile.ImageLocation != "blank.png")
                {
                    List<String> newList = new List<String>();
                    newList.Add("" + mapLocationX + ',' + mapLocationY);
                    String[] imageLoc = imageTile.ImageLocation.Split('.');
                    newList.Add(imageLoc[0]);
                    newList.Add("" + collisionCheckBox.Checked);
                    newList.Add("" + pushCheckBox.Checked);
                    if (objectBox.Text == "N/A")
                    {
                        newList.Add("N");
                    }
                    else
                    {
                        tempListString = new List<String>();
                        CreationForm creation = new CreationForm(this);
                        creation.ShowDialog();
                        foreach (String s in tempListString)
                        {
                            newList.Add(s);
                        }
                    }
                    objectsList.Add(newList);
                }
                if (counter == 1 && imageTile.ImageLocation != "blank")  // if the animation layer
                {
                    List<String> newList = new List<String>();
                    tempListString = new List<String>();
                    newList.Add("" + mapLocationX + ',' + mapLocationY);
                    String[] imageLoc = imageTile.ImageLocation.Split('.');
                    newList.Add(imageLoc[0]);
                    newList.Add("" + collisionCheckBox.Checked);
                    newList.Add("" + pushCheckBox.Checked);

                    AnimationInfo animationInfo = new AnimationInfo(this);
                    animationInfo.ShowDialog();
                    foreach (String s in tempListString)
                    {
                        newList.Add(s);
                    }
                    animationArray.Add(newList);
                    pic.Width = tempWidth / 2;
                    pic.Height = tempHeight / 2;
                }
                
            }
            catch (IndexOutOfRangeException)
            {
                MessageBox.Show("The tile will go outside the screen");
            }

            catch (NullReferenceException)
            {
                MessageBox.Show("Select a tile to place");
            }
            catch(UriFormatException)
            {
                MessageBox.Show("URIFormatExceptionHappened");
            }
            //this.Refresh();
        }


        /// <summary>
        /// Saves the file
        /// </summary>
        /// <param name="sender">The objecct being affected</param>
        /// <param name="e">The arguments associated with said event</param>
        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StreamWriter write = new StreamWriter(saveTextBox.Text);   // opens a new stream to wear the save text box says
            write.WriteLine(mapName);
            write.WriteLine(objects.GetLength(0) + "," + objects.GetLength(1));
            String[] bgLoc = bgBox.Text.Split('.');
            write.WriteLine(bgLoc[0]);                  // writes the location of the background image

            // writes the secondary map stuff
            List<String> checkNamesObj = CheckNames(objectsList);

            write.WriteLine(checkNamesObj.Count);
            for (int i = 0; i < checkNamesObj.Count; i++)
            {
                String[] shortenedName = checkNamesObj[i].Split('.');
                write.WriteLine(shortenedName[0]);
            }

            write.WriteLine(objectsList.Count);
            foreach (List<String> l in objectsList)
            {
                foreach (String s in l)
                {
                    write.Write(s + ":");
                }
                write.WriteLine();
            }

            // writes the animation map stuff
            checkNamesObj = CheckNames(animationArray);

            write.WriteLine(checkNamesObj.Count);
            for (int i = 0; i < checkNamesObj.Count; i++)
            {
                String[] shortenedName = checkNamesObj[i].Split('.');
                write.WriteLine(shortenedName[0]);
            }

            write.WriteLine(animationArray.Count);
            foreach (List<String> l in animationArray)
            {
                foreach (String s in l)
                {
                    write.Write(s + ":");
                }
                write.WriteLine();
            }
            write.Close();
        }


        /// <summary>
        /// Reads the .ktr files in
        /// </summary>
        /// <param name="filePath">The file that is being passed in</param>
        public void ReadFiles(String filePath)
        {
            StreamReader reader = new StreamReader(filePath);   // opens the stream to designated filepath
            mapName = reader.ReadLine();                        // sets the mapName to the first line
            saveTextBox.Text = mapName + ".ktr";
            String size = reader.ReadLine();                    // gets the mapSize from the second line
            String[] sizes = size.Split(',');                   // new array created to hold the sizes
            int row = int.Parse(sizes[0]);                      // parses the numbers to get rows and columns
            int col = int.Parse(sizes[1]);

            bgBox.Text = reader.ReadLine() + ".png";

            String doorAmount = reader.ReadLine();
            int doorNum = int.Parse(doorAmount);

            for (int i = 0; i < doorNum; i++)
            {
                doorTextBox.Text += reader.ReadLine() + "\n";
            }

            // scales the screen to the number of tiles
            if ((200 + ((row + 1) * 32)) > Width)
            {
                Width = (200 + ((row + 1) * 32)) + 32;
            }
            if ((3 + ((col + 1) * 32)) > Height)
            {
                Height = (3 + ((col + 1) * 32)) + 32;
            }

            objects = new PictureBox[row, col];
            objectsList = new List<List<String>>();
            animation = new PictureBox[row, col];
            animationArray = new List<List<String>>();

            for (int i = 0; i < objects.GetLength(0); i++)
            {
                for (int j = 0; j < objects.GetLength(1); j++)
                {
                    PictureBox pic = new PictureBox();
                    pic.ImageLocation = "blank.png";
                    pic.Image = new Bitmap(pic.ImageLocation);
                    int sizeX = pic.Image.Width;
                    int sizeY = pic.Image.Height;
                    while (sizeX % 16 != 0) { sizeX++; }
                    while (sizeY % 16 != 0) { sizeY++; }
                    pic.Size = new Size(sizeX / 2, sizeY / 2);
                    Point picPoint = new Point(230 + ((i + 1) * 16), 10 + ((j + 1) * 16));
                    pic.Location = picPoint;
                    pic.SizeMode = PictureBoxSizeMode.StretchImage;
                    objects[i, j] = pic;
                }
            }

            String pathTotalObj = reader.ReadLine();               // gets the total number of paths of pictures
            int pathNumObj = int.Parse(pathTotalObj);              // parse it to an int
            List<String> pathsObj = new List<String>();            // creates a list of strings to store the paths

            for (int i = 0; i < pathNumObj; i++)                   // goes through for the total number of paths adding them to a list
            {
                pathsObj.Add(reader.ReadLine());
            }
            int objectNum = int.Parse(reader.ReadLine());
            String objectReader;
            for (int i = 0; i < objectNum; i++)
            {
                objectReader = reader.ReadLine();
                String[] objectsArray = objectReader.Split(':');
                List<String> tempString = new List<String>();
                foreach (String s in objectsArray)
                {
                    if (s != "") { tempString.Add(s); }
                }
                objectsList.Add(tempString);
            }

            foreach(List<String> s in objectsList)
            {
                String[] coordinates = s[0].Split(',');
                int coordXPos = int.Parse(coordinates[0]);
                int coordsYPos = int.Parse(coordinates[1]);

                //int indexLoc = int.Parse(s[1]);

                //String imageLoc = pathsObj[indexLoc];
                String imageLoc = s[1];
                PictureBox pic = new PictureBox();
                pic.ImageLocation = imageLoc + ".png";
                pic.Image = new Bitmap(pic.ImageLocation);
                int sizeX = pic.Image.Width;
                int sizeY = pic.Image.Height;
                while (sizeX % 16 != 0) { sizeX++; }
                while (sizeY % 16 != 0) { sizeY++; }
                pic.Size = new Size(sizeX / 2, sizeY / 2);                                                 // shrinks the size of the picturebox
                Point picPoint = new Point(230 + ((coordXPos + 1) * 16), 10 + ((coordsYPos + 1) * 16));        // adds the proper amount to each
                pic.SizeMode = PictureBoxSizeMode.StretchImage;
                pic.Location = picPoint;
                pic.Name = "" + pic + coordXPos + coordsYPos;
                objects[coordXPos, coordsYPos] = pic;
            }

            for (int i = 0; i < animation.GetLength(0); i++)
            {
                for (int j = 0; j < animation.GetLength(1); j++)
                {
                    PictureBox pic = new PictureBox();
                    pic.ImageLocation = "blank.png";
                    pic.Image = new Bitmap(pic.ImageLocation);
                    int sizeX = pic.Image.Width;
                    int sizeY = pic.Image.Height;
                    while (sizeX % 16 != 0) { sizeX++; }
                    while (sizeY % 16 != 0) { sizeY++; }
                    pic.Size = new Size(sizeX / 2, sizeY / 2);
                    Point picPoint = new Point(230 + ((i + 1) * 16), 10 + ((j + 1) * 16));
                    pic.Location = picPoint;
                    pic.SizeMode = PictureBoxSizeMode.StretchImage;
                    animation[i, j] = pic;
                }
            }

            pathTotalObj = reader.ReadLine();               // gets the total number of paths of pictures
            pathNumObj = int.Parse(pathTotalObj);              // parse it to an int
            pathsObj = new List<String>();            // creates a list of strings to store the paths

            for (int i = 0; i < pathNumObj; i++)                   // goes through for the total number of paths adding them to a list
            {
                pathsObj.Add(reader.ReadLine());
            }

            objectNum = int.Parse(reader.ReadLine());
            for(int i = 0; i < objectNum; i++)
            {
                objectReader = reader.ReadLine();
                String[] objectsArray = objectReader.Split(':');
                List<String> tempString = new List<String>();
                foreach (String s in objectsArray)
                {
                    if (s != "") { tempString.Add(s); }
                }
                animationArray.Add(tempString);
            }

            foreach (List<String> s in animationArray)
            {
                String[] coordinates = s[0].Split(',');
                int coordXPos = int.Parse(coordinates[0]);
                int coordsYPos = int.Parse(coordinates[1]);

                //int indexLoc = int.Parse(s[1]);

                //String imageLoc = pathsObj[indexLoc];
                String imageLoc = s[1];
                PictureBox pic = new PictureBox();
                pic.ImageLocation = imageLoc + ".png";
                pic.Image = new Bitmap(pic.ImageLocation);
                int sizeX = pic.Image.Width;
                int sizeY = pic.Image.Height;
                while (sizeX % 16 != 0) { sizeX++; }
                while (sizeY % 16 != 0) { sizeY++; }
                pic.Size = new Size(sizeX / 2, sizeY / 2);                                                 // shrinks the size of the picturebox
                Point picPoint = new Point(230 + ((coordXPos + 1) * 16), 10 + ((coordsYPos + 1) * 16));        // adds the proper amount to each
                pic.SizeMode = PictureBoxSizeMode.StretchImage;
                pic.Location = picPoint;
                pic.Name = "" + pic + coordXPos + coordsYPos;
                animation[coordXPos, coordsYPos] = pic;
            }
            reader.Close();
            DrawLayer(objects, animation);
        }

        /// <summary>
        /// Goes through and checks to see how many names there are in order to reduce filePaths
        /// </summary>
        /// <returns>A List of all the different filePaths</returns>
        public List<String> CheckNames(List<List<String>> listObject)
        {
            List<String> toCheck = new List<String>();
            foreach (List<String> l in listObject)
            {
                if (!(toCheck.Contains(l[1])))
                {
                    toCheck.Add(l[1]);
                }
            }
            return toCheck;
        }

        /// <summary>
        /// Draws the layers
        /// </summary>
        /// <param name="layer">Layer to draw</param>
        public void DrawLayer(PictureBox[,] layer, PictureBox[,] remove)
        {
            for (int i = 0; i < layer.GetLength(0); i++)
            {
                for (int j = 0; j < layer.GetLength(1); j++)
                {
                    this.Controls.Remove(remove[i, j]);
                    this.Controls.Add(layer[i, j]);
                    layer[i, j].Click += new EventHandler(EditorForm_Click);
                }
            }

        }

        private void pathBox_Click(object sender, EventArgs e)
        {
            openFileTile.ShowDialog();
            pathBox.Text = openFileTile.SafeFileName;
        }


        private void bgBox_MouseClick(object sender, MouseEventArgs e)
        {
            openFileTile.ShowDialog();
            bgBox.Text = openFileTile.SafeFileName;
        }

        private void bgPicBox_OnMouseClick(object sender, MouseEventArgs e)
        {
            bgCoordsBox.Text = (e.X / 16) + "," + (e.Y / 16);
        }
        /// <summary>
        /// Submits the background
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgSubmit_Click(object sender, EventArgs e)
        {
            PictureBox bgPicBox = new PictureBox();
            Point bgPicBoxPoint = new Point(250 + objects.GetLength(0) * 16, 26);
            bgPicBox.Location = bgPicBoxPoint;
            bgPicBox.ImageLocation = bgBox.Text;
            bgPicBox.Image = new Bitmap(bgPicBox.ImageLocation);
            bgPicBox.Size = new Size(bgPicBox.Image.Width / 2, bgPicBox.Image.Height / 2);
            bgPicBox.SizeMode = PictureBoxSizeMode.StretchImage;
            bgPicBox.MouseClick += new MouseEventHandler(bgPicBox_OnMouseClick);
            this.Controls.Add(bgPicBox);
        }

        private void layerButton_Click_1(object sender, EventArgs e)
        {
            if (counter == 0)
            {
                DrawLayer(animation, objects);
                counter++;
                layerLabel.Text = "Animation Layer";
            }
            else if (counter == 1)
            {
                DrawLayer(objects, animation);
                counter--;
                layerLabel.Text = "Object Layer";
            }
        }


        /// <summary>
        /// Checks to see if placed tile collides with any others.  If it does, those tiles are removed
        /// </summary>
        /// <param name="pic">The object to check collision with</param>
        public void CheckRemoval(PictureBox pic)
        {
            List<int> indexToRemove = new List<int>();
            for (int i = 0; i < objectsList.Count; i++)
            {
                String[] locCheck = objectsList[i][0].Split(',');

                Image tempImg = new Bitmap(objectsList[i][1] + ".png");
                int leftCheck = 230 + (int.Parse(locCheck[0]) + 1) * 16;
                int topCheck = 10 + (int.Parse(locCheck[1]) + 1) * 16;
                int rightCheck = leftCheck + (tempImg.Width / 2);
                int bottomCheck = topCheck + (tempImg.Height / 2);

                int newObjTop = pic.Location.Y;
                int newObjBottom = pic.Location.Y + pic.Size.Height;
                int newObjLeft = pic.Location.X;
                int newObjRight = pic.Location.X + pic.Size.Width;

                if (!(newObjBottom <= topCheck || newObjTop >= bottomCheck || newObjRight <= leftCheck || newObjLeft >= rightCheck))
                {
                    indexToRemove.Add(i);
                }
            }

            for (int i = 0; i < indexToRemove.Count; i++)
            {
                objectsList.RemoveAt(indexToRemove[i] - i);
            }
        }
    }
}
